// sm3_standalone.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SM3_len 256
#define SM3_T1 0x79CC4519
#define SM3_T2 0x7A879D8A
#define SM3_IVA 0x7380166f
#define SM3_IVB 0x4914b2b9
#define SM3_IVC 0x172442d7
#define SM3_IVD 0xda8a0600
#define SM3_IVE 0xa96f30bc
#define SM3_IVF 0x163138aa
#define SM3_IVG 0xe38dee4d
#define SM3_IVH 0xb0fb0e4e

#define SM3_p1(x) (x^SM3_rotl32(x,15)^SM3_rotl32(x,23))
#define SM3_p0(x) (x^SM3_rotl32(x,9)^SM3_rotl32(x,17))
#define SM3_ff0(a,b,c) (a^b^c)
#define SM3_ff1(a,b,c) ((a&b)|(a&c)|(b&c))
#define SM3_gg0(e,f,g) (e^f^g)
#define SM3_gg1(e,f,g) ((e&f)|((~e)&g))
#define SM3_rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))

typedef struct {
    unsigned long state[8];
    unsigned long length;
    unsigned long curlen;
    unsigned char buf[64];
} SM3_STATE;

void SM3_compress(SM3_STATE *md) {
    unsigned long W[68];
    unsigned long W1[64];
    unsigned long A, B, C, D, E, F, G, H;
    unsigned long SS1, SS2, TT1, TT2, T;
    unsigned long FF, GG;
    int i, j;
    
    // BiToW
    for(i = 0; i < 16; i++) {
        W[i] = ((unsigned long)md->buf[i*4] << 24) |
               ((unsigned long)md->buf[i*4+1] << 16) |
               ((unsigned long)md->buf[i*4+2] << 8) |
               ((unsigned long)md->buf[i*4+3]);
    }
    
    for(i = 16; i < 68; i++) {
        unsigned long tmp = W[i-16] ^ W[i-9] ^ SM3_rotl32(W[i-3], 15);
        W[i] = SM3_p1(tmp) ^ SM3_rotl32(W[i-13], 7) ^ W[i-6];
    }
    
    // WToW1
    for(i = 0; i < 64; i++) {
        W1[i] = W[i] ^ W[i+4];
    }
    
    // CF
    A = md->state[0]; B = md->state[1]; C = md->state[2]; D = md->state[3];
    E = md->state[4]; F = md->state[5]; G = md->state[6]; H = md->state[7];
    
    for(j = 0; j < 64; j++) {
        if(j < 16) {
            T = SM3_T1;
            FF = SM3_ff0(A, B, C);
            GG = SM3_gg0(E, F, G);
        } else {
            T = SM3_T2;
            FF = SM3_ff1(A, B, C);
            GG = SM3_gg1(E, F, G);
        }
        
        SS1 = SM3_rotl32(SM3_rotl32(A, 12) + E + SM3_rotl32(T, j), 7);
        SS2 = SS1 ^ SM3_rotl32(A, 12);
        TT1 = FF + D + SS2 + W1[j];
        TT2 = GG + H + SS1 + W[j];
        
        D = C;
        C = SM3_rotl32(B, 9);
        B = A;
        A = TT1;
        H = G;
        G = SM3_rotl32(F, 19);
        F = E;
        E = SM3_p0(TT2);
    }
    
    md->state[0] ^= A; md->state[1] ^= B; md->state[2] ^= C; md->state[3] ^= D;
    md->state[4] ^= E; md->state[5] ^= F; md->state[6] ^= G; md->state[7] ^= H;
}

void SM3_init(SM3_STATE *md) {
    md->curlen = md->length = 0;
    md->state[0] = SM3_IVA;
    md->state[1] = SM3_IVB;
    md->state[2] = SM3_IVC;
    md->state[3] = SM3_IVD;
    md->state[4] = SM3_IVE;
    md->state[5] = SM3_IVF;
    md->state[6] = SM3_IVG;
    md->state[7] = SM3_IVH;
}

void SM3_update(SM3_STATE *md, const unsigned char *buf, size_t len) {
    while (len--) {
        md->buf[md->curlen++] = *buf++;
        if (md->curlen == 64) {
            SM3_compress(md);
            md->length += 512;
            md->curlen = 0;
        }
    }
}

void SM3_final(SM3_STATE *md, unsigned char *hash) {
    int i;
    
    md->length += md->curlen * 8;
    md->buf[md->curlen++] = 0x80;
    
    if (md->curlen > 56) {
        while (md->curlen < 64) md->buf[md->curlen++] = 0;
        SM3_compress(md);
        md->curlen = 0;
    }
    
    while (md->curlen < 56) md->buf[md->curlen++] = 0;
    
    // 添加长度（大端序）
    for (i = 63; i >= 56; i--) {
        md->buf[i] = md->length & 0xFF;
        md->length >>= 8;
    }
    
    SM3_compress(md);
    
    // 输出（大端序）
    for (i = 0; i < 8; i++) {
        hash[i*4] = (md->state[i] >> 24) & 0xFF;
        hash[i*4+1] = (md->state[i] >> 16) & 0xFF;
        hash[i*4+2] = (md->state[i] >> 8) & 0xFF;
        hash[i*4+3] = md->state[i] & 0xFF;
    }
}

void sm3_hash(const unsigned char *msg, size_t len, unsigned char *digest) {
    SM3_STATE ctx;
    SM3_init(&ctx);
    SM3_update(&ctx, msg, len);
    SM3_final(&ctx, digest);
}

int main() {
    unsigned char msg[] = "Hello SM3 Test";
    unsigned char digest[32];
    int i;
    
    printf("Testing SM3 implementation...\n");
    printf("Message: %s\n", msg);
    
    sm3_hash(msg, strlen((char*)msg), digest);
    
    printf("SM3 Hash: ");
    for (i = 0; i < 32; i++) {
        printf("%02x", digest[i]);
    }
    printf("\n\n");
    
    printf("Now verify with GmSSL:\n");
    printf("Run: echo -n 'Hello SM3 Test' | gmssl sm3\n");
    
    return 0;
}
